mod hell;

use std::sync::{Arc, Mutex, mpsc};
use std::time::Instant;
use std::{any, thread};
// use std::{any, thread};

const TOTAL: u64 = 1000000000;

fn main() {
    hell::llo::world::okk();
    // // let handle = thread::spawn(|| {
    // //     println!("Hello, world!");
    // // });
    // // handle.join().unwrap();
    //
    // let person = Person {
    //     name: String::from("Alice"),
    // };
    //
    // thread::spawn(move || {
    //     println!("Hello, {:?}", person);
    // });
    //
    // let person = Person {
    //     name: String::from("Alice"),
    // };
    //
    // thread::scope(|s| {
    //     s.spawn(|| {
    //         println!("Hello, {:?}", person);
    //     });
    // });
    //
    // thread::scope(|s| {
    //     s.spawn(|| {
    //         println!("Hello, {:?}", person);
    //     });
    // });

    count_time(serialized_calculate);

    count_time(parallel_calculate);

    count_time(scoped_calculate);

    count_time(channel_calculate);
}

fn channel_calculate() {
    let cpus = num_cpus::get() as u64;
    let chunk_size = TOTAL / cpus;
    let (tx, rx) = mpsc::channel();
    for i in 0..cpus {
        let start = i * chunk_size;
        let end = if i == cpus - 1 {
            TOTAL
        } else {
            (i + 1) * chunk_size
        };
        let tx = tx.clone();
        thread::spawn(move || {
            let mut local_sum = 0;
            for i in start..end {
                local_sum += i;
            }
            tx.send(local_sum).unwrap();
        });
    }
    drop(tx);
    let mut sum = 0;
    while let Ok(i) = rx.recv() {
        sum += i;
    }
    println!("sum is {}", sum);
}

fn scoped_calculate() {
    let cpus = num_cpus::get() as u64;
    let chunk_size = TOTAL / cpus;
    let sum = Mutex::new(0);
    thread::scope(|scope| {
        for i in 0..cpus {
            let start = i * chunk_size;
            let end = if i == cpus - 1 {
                TOTAL
            } else {
                (i + 1) * chunk_size
            };
            let sum_ref = &sum;
            scope.spawn(move || {
                let mut local_sum = 0;
                for i in start..end {
                    local_sum += i;
                }
                let mut sum = sum_ref.lock().unwrap();
                *sum += local_sum;
            });
        }
    });
    println!("sum is {}", sum.lock().unwrap());
}

fn parallel_calculate() {
    let cpus = num_cpus::get() as u64;
    let chunk_size = TOTAL / cpus;
    let sum = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for i in 0..cpus {
        let start = i * chunk_size;
        let end = if i == cpus - 1 {
            TOTAL
        } else {
            (i + 1) * chunk_size
        };
        let sum_clone = Arc::clone(&sum);
        let handle = thread::spawn(move || {
            let mut local_sum = 0;
            for i in start..end {
                local_sum += i;
            }
            let mut sum = sum_clone.lock().unwrap();
            *sum += local_sum;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("sum is {}", sum.lock().unwrap());
}

fn serialized_calculate() {
    let mut sum = 0u64;
    for i in 0..TOTAL {
        sum += i;
    }
    println!("sum is {}", sum);
}

fn count_time<F: FnOnce()>(f: F) {
    let name = any::type_name::<F>();
    let start = Instant::now();
    f();
    println!("[{name}] 总耗时: {} ms", start.elapsed().as_millis());
}

// #[derive(Debug)]
// struct Person {
//     name: String,
// }
